package com.edu.scnu.element;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;

import javax.swing.ImageIcon;

import com.edu.scnu.manager.ElementManager;
import com.edu.scnu.manager.GameElement;
import com.edu.scnu.manager.GameLoad;

public class Play extends ElementObj {

	/**
	 * 移动属性：
	 * 1.单属性 配合方向枚举类型使用；一次只能移动一个方向
	 * 2.双属性 上下和左右，配合boolean值使用。例如：true代表上，false代表下不动难以用boolean表示，需要另外一个变量来确定是否按下方向键
	 * 约定：0代表不动，1代表上，2代表下
	 * 3.4属性,这个就是上下左右都可以，boolean配合使用，true代表移动，false不移动 同时按住上和下时，后按的会重置先按的。
	 * 
	 * @说明 游戏中非常多的判定，建议灵活使用判定属性。很多状态值也使用判定属性 多状态可以使用map<泛型，boolean>；set<判定对象>
	 *     判定对象中有时间
	 * @问题 1.图片要读取到内存中：加载器，临时处理方式，手动编写存储到内存中
	 *     2.什么时候进行修改图片(因为图片中是在父类中的属性存储)
	 *     3.图片应该使用什么集合进行存储
	 * 
	 */

	private boolean left = false; // 左
	private boolean up = false; // 上
	private boolean right = false;// 右
	private boolean down = false; // 下
	public static int score = 0; // 分数
	private ImageIcon dieIcon;
	public ImageIcon getDieIcon() {
		return dieIcon;
	}

	public void setDieIcon(ImageIcon dieIcon) {
		this.dieIcon = dieIcon;
	}

	private int shotTime;

	private boolean pkType = false; // 攻击状态 true为攻击 false为停止

	public Play() {
	};

	public Play(int x, int y, int w, int h, ImageIcon icon) {
		super(x, y, w, h, icon);
	}

	@Override
	public ElementObj createElement(String str) {
		String[] split = str.split(",");
		this.setX(Integer.parseInt(split[0]));
		this.setY(Integer.parseInt(split[1]));
		ImageIcon icon2 = GameLoad.imgMap.get(split[2]);
		this.setW(icon2.getIconWidth());
		this.setH(icon2.getIconHeight());
		this.setIcon(icon2);
		ImageIcon iconDie = GameLoad.imgMap.get("die");
		this.setDieIcon(iconDie);
		this.setDieIconW(iconDie.getIconWidth());
		this.setDieIconH(iconDie.getIconHeight());
		this.setShowH(this.getDieIconH());
		this.setShowW(this.getDieIconW()/8);
		this.setHp(3);
		this.setAttack(1);
		this.setSpeed(5);
		this.pkType = true;
		this.setShotTime(20);
		return this;
	}

	/**
	 * @待解决问题 传输格式"x:${横坐标},y:${纵坐标},n:${子弹图片的键，具体参考GameData.pro文件,例“fire”}
	 * @return
	 */
	public String getFile() { // 定义的方法:子弹位置
		int x = this.getX();
		int y = this.getY();
		// 子弹发射的时候给予固定轨迹

		x = x + 20;
		y = y - 25;
		// 这里留白，还需要对子弹位置进行微调，等能够显示飞机位置再填写

		return "x:" + x + ",y:" + y + ",n:" + "fire";
	}

	/**
	 * 面向对象的第一个思想：对象自己的事情自己做
	 */
	@Override
	public void showElement(Graphics g) {
		if (this.isLive()) {
			g.drawImage(this.getIcon().getImage(), this.getX(), this.getY(), this.getW(), this.getH(), null);
		}
		else {
			g.drawImage(this.getDieIcon().getImage(), this.getX(), this.getY(), this.getX() + this.getW(), 
					this.getY() + this.getH(),this.getShowX(), this.getShowY(), this.getShowX()+ this.getShowW(), this.getShowY() + this.getShowH(), null);
		}
		g.setColor(Color.red);
		g.setFont(new Font("微软雅黑", Font.BOLD, 18));
		g.drawString("当前得分：" + this.getScore(), 20, 30);
		g.drawString("当前血量：" + this.getHp(), 20, 60);
	}

	/**
	 * @说明 重写方法，重写的要求为：方法名称和参数类型序列，必须和父类的方法一样
	 * @重点 监听的数据需要改变状态值，而不是数值
	 */
	@Override
	public void keyClick(boolean bl, int key) {
		if (bl) { // 按下
			switch (key) {
				case 37:
				case 65:
					this.right = false;
					this.up = false;
					this.down = false;
					this.left = true;
					break;
				case 38:
				case 87:
					this.right = false;
					this.left = false;
					this.down = false;
					this.up = true;
					break;
				case 39:
				case 68:
					this.down = false;
					this.up = false;
					this.left = false;
					this.right = true;
					break;
				case 40:
				case 83:
					this.left = false;
					this.right = false;
					this.up = false;
					this.down = true;
					break;
				// case 32:
				// this.pkType = true;
				// break;
			}
		} else {
			switch (key) {
				case 37:
				case 65:
					this.left = false;
					break;
				case 38:
				case 87:
					this.up = false;
					break;
				case 39:
				case 68:
					this.right = false;
					break;
				case 40:
				case 83:
					this.down = false;
					break;
				// case 32:
				// this.pkType = false;
				// break; // 关闭攻击
			}
		}
	}

	@Override
	public void move(long gameTime) {
		if (this.left && this.getX() > 0) {
			this.setX(this.getX() - this.getSpeed());
		}
		if (this.up && this.getY() > 0) {
			this.setY(this.getY() - this.getSpeed());
		}
		if (this.right && this.getX() < 580 - this.getW()) { // 坐标的调整自行完成
			this.setX(this.getX() + this.getSpeed());
		}
		if (this.down && this.getY() < 760 - this.getH()) {
			this.setY(this.getY() + this.getSpeed());
		}
	}

	@Override
	public void updateImage(long gameTime) {
		this.setIcon(GameLoad.imgMap.get("play"));// 这里上传的是飞机名字
	}

	/**
	 * @额外问题 1.重写的方法的访问修饰符是否可以修改
	 *       2.add方法是否可以自动抛出异常
	 * @重写规则 1.重写方法的方法名称和返回值必须和父类的一样
	 *       2.重写的方法的传入参数类型序列，必须和父类的一样
	 *       3.重写的方法访问修饰符只能比父类的更加宽泛
	 *       比方说：父类的方法是受保护的，但是现在需要在非子类调用
	 *       可以直接子类继承，重写并super.父类方法。public方法。
	 *       4.重写的方法抛出的异常，不可以比父类的更加宽泛
	 * @说明 子弹的添加需要的是发射者的坐标位置，发射者的方向，如果你可以变换子弹（思考，怎么处理）
	 */
	private long fileTime = 0;

	@Override
	protected void add(long gameTime) {
		if (!this.pkType) { // 如果攻击状态为假
			return;
		}
		if (gameTime < fileTime + this.getShotTime() && fileTime > 0) {
			return;
		}
		fileTime = gameTime;
		// this.pkType = false; // 按一次，发射一个子弹。拼手速。
		// new PlayFile(); // 构造一个类需要做比较多的工作,可以选择一种方式,使用小工厂
		// 将构造对象的多个步骤封装成一个方法,返回值直接是这个对象
		ElementObj obj = GameLoad.getObj("file");
		ElementObj element = obj.createElement(this.toString()); // 以后的框架学习中会碰到
		// 会帮助返回对象的实体,并初始化数据
		ElementManager.getManager().addElement(element, GameElement.PLAYFILE);
		// 如果要控制子弹速度等，还需要代码编写
	}

	@Override
	public String toString() {
		// {x:3, y:5} json格式
		return getFile();
	}

	/**
	 * @说明 展示分数
	 */
	public int getScore() {
		return score;
	}

	@Override
	public void beAttacked(int attack) {
		this.setHp(this.getHp() - attack);
		// System.out.println(this.getHp());
		if (this.getHp() <= 0) {
			super.beAttacked(attack);
		}
	}
	
	public Rectangle getRectangle() {
		// 后期可以对数据进行处理
		return new Rectangle(this.getX()+ this.getW() / 4, this.getY() + this.getH() / 4, this.getW()/2, this.getH()/2);
	}
	
	public int getShotTime() {
		return shotTime;
	}

	public void setShotTime(int shotTime) {
		this.shotTime = shotTime;
	}
	
	private int dieIconW;
	public int getDieIconW() {
		return dieIconW;
	}

	public void setDieIconW(int dieIconW) {
		this.dieIconW = dieIconW;
	}

	public int getDieIconH() {
		return dieIconH;
	}

	public void setDieIconH(int dieIconH) {
		this.dieIconH = dieIconH;
	}

	public int getShowW() {
		return showW;
	}

	public void setShowW(int showW) {
		this.showW = showW;
	}

	public int getShowH() {
		return showH;
	}

	public void setShowH(int showH) {
		this.showH = showH;
	}

	public int getShowX() {
		return showX;
	}

	public void setShowX(int showX) {
		this.showX = showX;
	}

	public int getShowY() {
		return showY;
	}

	public void setShowY(int showY) {
		this.showY = showY;
	}

	private int dieIconH;
	private int showW;
	private int showH;
	private int showX = 0;
	private int showY = 0;
	private long dieTimer = 10;

	@Override
	public void die(long gameTime) {
		if (this.getShowX() <= this.getDieIconW()) {
			this.setCanRmove(false);
		}
		else
		{
			this.setCanRmove(true);
		}
		if (gameTime < fileTime + this.getDieTimer() && fileTime > 0) {
			return;
		}
		fileTime = gameTime;
		this.setShowX(this.getShowX() + this.getShowW());
	}

	public long getDieTimer() {
		return dieTimer;
	}

	public void setDieTimer(long dieTimer) {
		this.dieTimer = dieTimer;
	}
}
